package com.mhy.crash.utils;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;

import androidx.annotation.NonNull;

import com.mhy.crash.R;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;

public class HYCrashUtils {

    /**
     * 把Throwable解析成CrashModel实体
     */
    public static CrashModel parseCrash(Context context, Throwable ex) {
        CrashModel model = new CrashModel();
        try {
            model.setEx(ex);
            model.setTime(System.currentTimeMillis());
            if (ex.getCause() != null) {
                ex = ex.getCause();
            }
            model.setPackageName(context.getPackageName());
            model.setExceptionMsg(ex.getMessage());
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            ex.printStackTrace(pw);
            pw.flush();
            String exceptionType = ex.getClass().getName();

            StackTraceElement element = parseThrowable(context, ex);
            if (element == null) return model;

            model.setLineNumber(element.getLineNumber());
            model.setClassName(element.getClassName());
            model.setFileName(element.getFileName());
            model.setMethodName(element.getMethodName());
            model.setExceptionType(exceptionType);

            model.setFullException(sw.toString());

            model.setVersionCode(HYCrashUtils.getVersionCode(context));
            model.setVersionName(HYCrashUtils.getVersionName(context));
        } catch (Exception e) {
            return model;
        }
        return model;
    }

    /**
     * 把Throwable解析成StackTraceElement
     */
    public static StackTraceElement parseThrowable(Context context, Throwable ex) {
        if (ex == null || ex.getStackTrace() == null || ex.getStackTrace().length == 0) return null;
        StackTraceElement element;
        String packageName = context.getPackageName();
        for (StackTraceElement ele : ex.getStackTrace()) {
            if (ele.getClassName().contains(packageName)) {
                element = ele;
                return element;
            }
        }
        element = ex.getStackTrace()[0];
        return element;
    }


    /**
     * 杀掉App进程
     */
    public static void killAct(Context context) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.AppTask> tasks = am.getAppTasks();

        if (!tasks.isEmpty()) {
            ActivityManager.AppTask topTask = tasks.get(0);
            topTask.finishAndRemoveTask();
        }
    }

    public static void killApp() {
        Log.e("HYCrash", "killApp");
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    /**
     * 获取分享的文本
     */
    public static String getShareText(Context context, CrashModel model) {
        StringBuilder builder = new StringBuilder();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd_HH:mm", Locale.getDefault());

        builder.append(context.getString(R.string.simpleCrashInfo))
                .append("\n")
                .append(model.getExceptionMsg())
                .append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        builder.append(context.getString(R.string.simpleClassName))
                .append(model.getFileName()).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        builder.append(context.getString(R.string.simpleFunName)).append(model.getMethodName()).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        builder.append(context.getString(R.string.simpleLineNum)).append(model.getLineNumber()).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        builder.append(context.getString(R.string.simpleExceptionType)).append(model.getExceptionType()).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        builder.append(context.getString(R.string.simpleTime)).append(df.format(model.getTime())).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        CrashModel.Device device = model.getDevice();

        builder.append(context.getString(R.string.simpleModel)).append(model.getDevice().getModel()).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        builder.append(context.getString(R.string.simpleBrand)).append(model.getDevice().getBrand()).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        String platform = "Android " + device.getRelease() + "-" + device.getVersion();
        builder.append(context.getString(R.string.simpleVersion)).append(platform).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        builder.append("CPU-ABI:").append(device.getCpuAbi()).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        builder.append("versionCode:").append(model.getVersionCode()).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        builder.append("versionName:").append(model.getVersionName()).append("\n");
        builder.append("\n");//空一行，好看点，(#^.^#)

        builder.append(context.getString(R.string.simpleAllInfo))
                .append("\n")
                .append(model.getFullException()).append("\n");

        return builder.toString();
    }

    /**
     * 获取缓存目录
     */
    public static String getCrashCachePath(Context context) {
        try {
            String path = context.getExternalCacheDir().getAbsolutePath() + File.separator + "crash";
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
            return path;
        } catch (Exception e) {
            String path = context.getCacheDir().getAbsolutePath() + File.separator + "crash";
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
            return path;
        }
    }

    /**
     * 删除 crash日志文件
     */
    public static void clearCrashCache(Context context) {
        File file = new File(getCrashCachePath(context));
        if (file.exists()) {
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
                for (File f : files) {
                    if (f.exists()) {
                        f.delete();
                    }
                }
            }
        }
    }

    /**
     * 保存文本到文件
     */
    public static void saveTextToFile(Context context, String text, String fileName) throws IOException {
        String logPath = getCrashCachePath(context) + File.separator + fileName;
        File file = new File(logPath);
        saveTextToFile(text, file);
    }

    public static void saveTextToFile(Context context, String text) throws IOException {
        String time = String.valueOf(System.currentTimeMillis());
        String fileName = "crash-" + time + ".txt";
        saveTextToFile(context, text, fileName);
    }

    /**
     * 保存文本到文件
     */
    public static void saveTextToFile(String text, File file) throws IOException {
        FileWriter writer = new FileWriter(file);
        writer.write(text);
        writer.flush();
        writer.close();
    }

    /**
     * set值是不会改变原始数据的
     * 通过getPackageManager().getApplicationInfo返回的applicationInfo始终是一个数据副本。
     * 如果动态set设置的话，也只是改变了副本的值，并没有改变原数据。因此再次获取applicationInfo还是个原数据的副本，仍然是旧值
     */
    public static Bundle getAppMetaDate(@NonNull Context mContext) {
        try {
            PackageManager packageManager = mContext.getPackageManager();
            ApplicationInfo appInfo = packageManager.getApplicationInfo(mContext.getPackageName(), PackageManager.GET_META_DATA);
            return appInfo.metaData;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return mContext.getApplicationInfo().metaData;
    }

    /**
     * 获取versionCode
     */
    public static String getVersionCode(Context context) {
        String versionCode = "";
        try {
            PackageManager pm = context.getPackageManager();
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            versionCode = String.valueOf(packageInfo.versionCode);
        } catch (Exception e) {

        }
        return versionCode;
    }

    /**
     * 获取versionName
     */
    public static String getVersionName(Context context) {
        String versionName = "";
        try {
            PackageManager pm = context.getPackageManager();
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            versionName = String.valueOf(packageInfo.versionName);
        } catch (Exception e) {

        }
        return versionName;
    }

    /**
     * 用反射获取Application
     */
    public static Application getApplicationByReflect() {
        try {
            @SuppressLint("PrivateApi")
            Class<?> activityThread = Class.forName("android.app.ActivityThread");
            Object thread = activityThread.getMethod("currentActivityThread").invoke(null);
            Object app = activityThread.getMethod("getApplication").invoke(thread);
            if (app == null) {
                throw new NullPointerException("you should init first");
            }
            return (Application) app;
        } catch (Exception e) {
            e.printStackTrace();
        }
        throw new NullPointerException("you should init first");
    }

}
